package org.zoomdev.zoom.web.test;


import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.common.io.Io;
import org.zoomdev.zoom.common.json.JSON;
import org.zoomdev.zoom.common.utils.CollectionUtils;

import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpServletResponseImpl {
    private  StringWriter stringWriter;
    private final Map<String, List<String>> headers = new HashMap<>();
    private String encoding = "utf8";
    private MockServletOutputStream outputStream;
    private PrintWriter writer;
    private String contentType;
    private int status;

    private int contentLength;

    public void setContentLength(int value) {
        this.contentLength = value;
    }

    public void addHeader(String name, String value) {
        headers.compute(name, (k, v) -> {
            if (v == null) {
                return CollectionUtils.asList(value);
            }
            v.add(value);
            return v;
        });
    }

    public void clear(){
        headers.clear();
        if(outputStream!=null){
            Io.close(outputStream);
            outputStream = null;
        }
        if(writer!=null){
            stringWriter = null;
            Io.close(writer);
        }
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int sc) {
        status = sc;
    }

    public void setHeader(String name, String value) {
        headers.put(name, CollectionUtils.asList(value));
    }

    public String getCharacterEncoding() {
        return encoding;
    }

    public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
        this.encoding = env;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String type) {
        headers.put("Content-Type", CollectionUtils.asList(type));
        contentType = type;
    }

    public PrintWriter getWriter() throws IOException {
        if (writer == null) {
            stringWriter = new StringWriter();
            writer = new PrintWriter(stringWriter);
        } else {
            if (outputStream != null)
                throw new ZoomException("Stream is already opened");
        }
        return writer;
    }

    public ServletOutputStream getOutputStream() throws IOException {
        if (outputStream == null) {
            outputStream = MockUtils.outputStream();
        } else {
            throw new ZoomException("Stream is already opened");
        }
        return outputStream;
    }

    public String string() {
        if (writer != null) {
            return stringWriter.toString();
        }

        return new String(outputStream.bytes(), StandardCharsets.UTF_8);
    }

    public byte[] bytes() {
        if (outputStream != null) {
            return outputStream.bytes();
        }
        return stringWriter.toString().getBytes(StandardCharsets.UTF_8);
    }

    public <T> T json(Type type) {
        return JSON.parse(string(), type);
    }
}
